package ginplus

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/hongzhaomin/hzm-common-go/coll"
	"gitee.com/hongzhaomin/hzm-common-go/concurrent"
	"gitee.com/hongzhaomin/hzm-common-go/easylog"
	"gitee.com/hongzhaomin/hzm-common-go/streams"
	"gitee.com/hongzhaomin/hzm-common-go/strutil"
	"gitee.com/hongzhaomin/hzm-common-go/toolkit"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"log/slog"
	"net/http"
	"reflect"
	"strings"
	"time"
	"unsafe"
)

const (
	rootPath   = "/"    // 根路径
	ginTagForm = "form" // gin表单解析tag名称
	ginTagUri  = "uri"  // gin路径参数解析tag名称
)

// WebContext web容器对象
type WebContext struct {
	logger               easylog.Logger                           // 日志对象
	ctrlResolver         *controllerResolver                      // controller解析器
	contextPath          string                                   // 项目路径配置，默认 "/"
	serverPort           string                                   // 服务端口配置，默认 8080
	useBuiltinRespStruct bool                                     // 是否使用内置响应结构体，默认true
	globalPanicHandler   GlobalPanicHandler                       // 全局异常处理器
	ginEngine            *gin.Engine                              // gin引擎
	httpServer           *http.Server                             // http服务
	url2MappingMap       *concurrent.Map[string, *HandlerMapping] // 路径和映射器map
	httpSession          HttpSession                              // session会话对象
	httpHandler          HttpHandler                              // http处理器
	filters              []Filter                                 // 过滤器
}

func NewWebContext(ginEngine *gin.Engine) *WebContext {
	if ginEngine == nil {
		panic("ginEngine must not be nil")
	}
	logger := easylog.NewDefaultLogger(slog.LevelDebug)
	webCtx := &WebContext{
		logger: logger,
		ctrlResolver: &controllerResolver{
			ctrlList: make([]iController, 0, 16),
		},
		contextPath:          rootPath,
		serverPort:           "8080",
		useBuiltinRespStruct: true,
		ginEngine:            ginEngine,
		url2MappingMap:       concurrent.NewMap[string, *HandlerMapping](),
		httpSession:          NewDefaultHttpSession(logger),
	}
	webCtx.httpHandler = NewCommonHttpHandler(webCtx, nil)
	return webCtx
}

func (wc *WebContext) SetLogger(logger easylog.Logger) {
	if logger == nil {
		panic("logger must not be nil")
	}
	wc.logger = logger
}

func (wc *WebContext) AddControllers(controllers ...iController) {
	wc.ctrlResolver.ctrlList = append(wc.ctrlResolver.ctrlList, controllers...)
}

func (wc *WebContext) SetContextPath(contextPath string) {
	wc.contextPath = contextPath
}

func (wc *WebContext) getContextPath() string {
	return strutil.JoinPaths(rootPath, wc.contextPath)
}

func (wc *WebContext) SetServerPort(serverPort string) {
	wc.serverPort = serverPort
}

func (wc *WebContext) getServerPort() string {
	if strutil.IsBlank(wc.serverPort) {
		return "8080"
	}
	return wc.serverPort
}

func (wc *WebContext) SetUseBuiltinRespStruct(useBuiltinRespStruct bool) {
	wc.useBuiltinRespStruct = useBuiltinRespStruct
}

func (wc *WebContext) SetGlobalPanicHandler(globalPanicHandler GlobalPanicHandler) {
	wc.globalPanicHandler = globalPanicHandler
}

func (wc *WebContext) SetHttpSession(httpSession HttpSession) {
	if httpSession != nil {
		wc.httpSession = httpSession
	}
}

func (wc *WebContext) GetHttpSession() HttpSession {
	return wc.httpSession
}

func (wc *WebContext) SetHttpHandler(httpHandler HttpHandler) {
	if httpHandler != nil {
		wc.httpHandler = httpHandler
	}
}

func (wc *WebContext) AddFilters(filters ...Filter) {
	wc.filters = append(wc.filters, filters...)
}

func (wc *WebContext) prepareHttpServer() {
	wc.logger.Info("Starting http server [GINPLUS]")
	// 注册自定义中间件
	wc.ginEngine.Use(wc.ginMiddleware)
	wc.logger.Info("Starting gin engine with port(s): %s (http)", wc.getServerPort())
	// 注册路由
	contextPath := wc.getContextPath()
	// 主分组
	root := wc.ginEngine.Group(contextPath)
	wc.ctrlGroup(root)
}

func (wc *WebContext) StartHttpServer() {
	wc.prepareHttpServer()
	contextPath := wc.getContextPath()
	// 获取配置端口，启动服务
	port := wc.getServerPort()
	if strutil.IsNotBlank(port) {
		wc.logger.Info("Ginplus started on port(s): %s (http) with context path '%s'", port, contextPath)
		_ = wc.ginEngine.Run(strutil.Colon + port)
	} else {
		// listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
		wc.logger.Info("Ginplus started on port(s): 8080 (http) with context path '%s'", contextPath)
		_ = wc.ginEngine.Run()
	}
}

func (wc *WebContext) StartHttpServerAsync() {
	wc.prepareHttpServer()

	port := wc.getServerPort()
	wc.httpServer = &http.Server{
		Addr:    strutil.Colon + port,
		Handler: wc.ginEngine.Handler(),
	}

	go func() {
		if err := wc.httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
			wc.logger.Error("Failed to start http server on port %s: %s", port, err)
		}
	}()
	wc.logger.Info("Ginplus started on port(s): %s (http) with context path '%s'", port, wc.getContextPath())
}

func (wc *WebContext) Shutdown() {
	if wc.httpServer != nil {
		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancel()
		if err := wc.httpServer.Shutdown(ctx); err != nil {
			wc.logger.Error("Failed to shutdown http server: %s", err)
		} else {
			wc.logger.Info("Shutdown http server successfully")
		}
	}
}

func (wc *WebContext) ginMiddleware(ctx *gin.Context) {
	fullPath := ctx.Request.URL.Path
	mapping, ok := wc.getHandlerMapping(fullPath)
	if !ok {
		// 请求路径找不到 404
		PrintErrPage(ctx.Writer, http.StatusNotFound)
		return
	}
	if mapping.method != ctx.Request.Method {
		// 请求方式不匹配 405
		PrintErrPage(ctx.Writer, http.StatusMethodNotAllowed)
		return
	}

	ctx.Next()
}

func (wc *WebContext) ctrlGroup(root *gin.RouterGroup) {
	wc.logger.Info("Resolving controllers")
	// 解析controller获取处理器调用链切片
	mappingChains := wc.ctrlResolver.resolveCtrlList()
	wc.logger.Info("The %d controller have completed resolve", len(wc.ctrlResolver.ctrlList))
	// 遍历处理器调用链，注册http
	for _, mappingChain := range mappingChains {
		ctrlPath := mappingChain.requestMapping
		ctrlGroup := root.Group(ctrlPath)
		for _, mapping := range mappingChain.handlerMappings {
			basePath := wc.getContextPath()
			fullPath := strutil.JoinPaths(strutil.JoinPaths(basePath, ctrlPath), mapping.url)
			wc.url2MappingMap.Store(fullPath, mapping)
			wc.mappingRegis4Http(ctrlGroup, mapping, wc.httpHandler.HandleFunc)
			wc.logger.Info("%-4s %-25s --> %s.%s", mapping.method, fullPath, mappingChain.ctrlName, mapping.fun.funName)
		}
	}
	wc.logger.Info("The %d controller have completed registration", len(mappingChains))
}

func (wc *WebContext) mappingRegis4Http(ctrlGroup *gin.RouterGroup, mapping *HandlerMapping, handler gin.HandlerFunc) {
	url := mapping.url
	method := mapping.method
	switch method {
	case http.MethodGet:
		ctrlGroup.GET(url, handler)
	case http.MethodPost:
		ctrlGroup.POST(url, handler)
	case http.MethodPut:
		ctrlGroup.PUT(url, handler)
	case http.MethodDelete:
		ctrlGroup.DELETE(url, handler)
	default:
		wc.logger.Error("暂不支持http请求：%s，请求url为：%s", method, url)
		panic(errors.New("不支持的http请求"))
	}
}

func (wc *WebContext) getHandlerMapping(fullPath string) (*HandlerMapping, bool) {
	return wc.url2MappingMap.Load(fullPath)
}

// HttpHandler 处理器接口
type HttpHandler interface {
	HandleFunc(ctx *gin.Context)
	BeforeInvoke(ctx *gin.Context, mapping *HandlerMapping, rvParams []reflect.Value) bool
	AfterInvoke(ctx *gin.Context, mapping *HandlerMapping, rvParams []reflect.Value, result any) bool
}

func NewCommonHttpHandler(webCtx *WebContext, child HttpHandler) *CommonHttpHandler {
	return &CommonHttpHandler{
		HttpHandler: child,
		webContext:  webCtx,
		processor:   NewDefaultProcessor(webCtx.httpSession),
	}
}

var _ HttpHandler = (*CommonHttpHandler)(nil)

// CommonHttpHandler 通用http处理器
type CommonHttpHandler struct {
	HttpHandler // 子类
	webContext  *WebContext
	processor   MappingHandlerProcessor
}

func (chh *CommonHttpHandler) getThis() HttpHandler {
	var my HttpHandler = chh
	if chh.HttpHandler != nil {
		my = chh.HttpHandler
	}
	return my
}

func (chh *CommonHttpHandler) HandleFunc(ctx *gin.Context) {
	// 全局异常处理
	globalPanicHandler := chh.webContext.globalPanicHandler
	if globalPanicHandler != nil {
		// 自定义全局异常处理
		defer chh.customerGlobalPanicHandler(globalPanicHandler, ctx)
	} else {
		// 默认全局异常处理
		defer chh.defaultGlobalPanicHandler(ctx)
	}

	// 根据路径获取处理器
	mapping, ok := chh.webContext.getHandlerMapping(ctx.FullPath())
	if !ok {
		PrintErrPage(ctx.Writer, http.StatusNotFound)
		return
	}

	// 准备参数
	rvParams, existCtx := chh.prepareParams(mapping.fun, ctx)

	chain := NewDefaultFilterChain(ctrlMethodInvokeFilterChain(func() {
		chh.invoke(ctx, mapping, rvParams, existCtx)
	}))
	chain.AddFilter(chh.webContext.filters...)
	chain.DoFilter(NewHandlerMappingWrapper(mapping, ctx, rvParams))

}

func (chh *CommonHttpHandler) invoke(ctx *gin.Context, mapping *HandlerMapping, rvParams []reflect.Value, existCtx bool) {
	// 扩展处理器调用前逻辑
	if ok := chh.getThis().BeforeInvoke(ctx, mapping, rvParams); !ok {
		return
	}

	// 调用处理器函数
	data := chh.doInvoke(mapping.fun.rvFun, rvParams)

	// 扩展处理器调用后逻辑
	if ok := chh.getThis().AfterInvoke(ctx, mapping, rvParams, data); !ok {
		return
	}

	// 响应处理
	switch mapping.handlerChain.ctrlType {
	case controller:
		chh.responseHtml(data, existCtx, ctx)
	case restController:
		chh.responseJson(data, existCtx, ctx, mapping.fun)
	default:
		chh.responseJson(data, existCtx, ctx, mapping.fun)
	}
}

func (chh *CommonHttpHandler) defaultGlobalPanicHandler(ctx *gin.Context) {
	use := chh.webContext.useBuiltinRespStruct
	var err = recover()
	if err != nil {
		if !use {
			// 不使用内置响应结构体，继续将错误抛出
			panic(err)
		} else {
			chh.webContext.logger.Error("[%s]请求异常，%v", ctx.FullPath(), err)
			switch e := err.(type) {
			case *bizError:
				ctx.JSON(http.StatusOK, Fail2[any](e.Code, e.Msg))
			case string:
				ctx.JSON(http.StatusOK, Fail[any](e))
			case error:
				ctx.JSON(http.StatusOK, Fail[any](e.Error()))
			default:
				ctx.JSON(http.StatusOK, Fail[any]("服务开小差了"))
			}
		}
	}
}

func (chh *CommonHttpHandler) customerGlobalPanicHandler(globalPanicHandler GlobalPanicHandler, ctx *gin.Context) {
	var err = recover()
	if err != nil {
		errData := globalPanicHandler.ErrorHandle(err)
		if errData == nil {
			// 返回为nil, 表示未开启全局异常处理配置，继续将错误抛出
			panic(err)
		}
		ctx.JSON(http.StatusOK, errData)
	}
}

func (chh *CommonHttpHandler) prepareParams(fun HandlerMethod, ctx *gin.Context) ([]reflect.Value, bool) {
	logger := chh.webContext.logger
	// 构造方法入参列表
	existCtx := false
	rvParams := make([]reflect.Value, 0)
	for _, funParam := range fun.funParams {
		paramName := funParam.pName
		// 判断是否为特殊类型参数
		definedSpecialParamType := funParam.definedSpecialParamType
		if ginCtx.is(definedSpecialParamType) {
			rvParams = append(rvParams, reflect.ValueOf(ctx))
			existCtx = true
			continue
		} else if mulFile.is(definedSpecialParamType) {
			if strutil.IsBlank(paramName) {
				paramName = "file"
			}
			file, err := ctx.FormFile(paramName)
			if err != nil {
				logger.Error("单文件参数绑定失败，%v", err)
				panic(errors.New("单文件参数绑定失败"))
			}
			rvParams = append(rvParams, reflect.ValueOf(file))
			continue
		} else if mulForm.is(definedSpecialParamType) {
			form, err := ctx.MultipartForm()
			if err != nil {
				logger.Error("多文件参数绑定失败，%v", err)
				panic(errors.New("多文件参数绑定失败"))
			}
			rvParams = append(rvParams, reflect.ValueOf(form))
			continue
		}

		// 创建实例
		var rvParamPtr reflect.Value
		rtParam := funParam.rtParam
		defaultValMap := funParam.defaultValMap

		switch rtParam.Kind() {
		case reflect.Struct:
			// 创建结构体实例，拿到指针
			rvParamPtr = reflect.New(rtParam)
			// form请求参数方式并且不存在form TAG
			form := strings.Contains(binding.Default(ctx.Request.Method, ctx.ContentType()).Name(), ginTagForm)
			if form && toolkit.NotExistTag(rtParam, ginTagForm) {
				// 构建新结构体，然后将数据绑定到新的结构体上
				rtParamNew := chh.copyStructFields(rtParam, strutil.Empty, defaultValMap)
				rvParamNew := reflect.New(rtParamNew)
				if err := ctx.ShouldBind(rvParamNew.Interface()); err != nil {
					logger.Error("数据绑定失败，%v", err)
					panic(errors.New("数据绑定失败"))
				}
				// 将新结构体值的指针转化为 rtParam 结构体类型的指针
				rvParamPtr = reflect.NewAt(rtParam, unsafe.Pointer(rvParamNew.Pointer()))
				// 将新结构体转成json，再将json转成原始结构体
				// 从而达到将数据绑定到原始结构体上的目的
				//toJson := toolkit.ToJson3(rvParamNew.Interface())
				//toolkit.ToObj(toJson, rvParamPtr.Interface())
			} else {
				// 做数据绑定
				if err := ctx.ShouldBind(rvParamPtr.Interface()); err != nil {
					logger.Error("数据绑定失败，%v", err)
					panic(errors.New("数据绑定失败"))
				}
				chh.setDefaultVal(rvParamPtr.Elem(), strutil.Empty, defaultValMap)
			}
			// 尝试绑定路径参数
			chh.tryToBindUri(ctx, rvParamPtr.Interface())
			// 不能这么做了，因为如果rvParamPtr指向的值是nil，那么再调用 reflect.Value.Addr() 方法则会panic
			//// 统一转化为指针指向的值
			//rvParamPtr = rvParamPtr.Elem()
		case reflect.Map:
			// 创建 map 体实例
			rvParam := reflect.MakeMap(rtParam)
			// 尝试绑定路径参数
			chh.tryToBindUri(ctx, rvParam.Interface())
			// 做数据绑定
			if err := ctx.ShouldBind(rvParam.Interface()); err != nil {
				logger.Error("数据绑定失败，%v", err)
				panic(errors.New("数据绑定失败"))
			}
			// 统一转为指针
			rvParamPtr = reflect.New(rtParam)
			rvParamPtr.Elem().Set(rvParam)
		case reflect.Slice:
			var rvParam reflect.Value
			if strutil.IsBlank(paramName) {
				// 如果未指定参数名，则认为请求为body方式，使用shouldBind方式绑定数据
				paramTemp := reflect.MakeSlice(rtParam, 0, 0).Interface()
				// 创建临时切片绑定数据，类型为参数定义的类型
				if err := ctx.ShouldBind(&paramTemp); err != nil {
					logger.Error("数据绑定失败，%v", err)
					panic(errors.New("数据绑定失败"))
				}
				// 再利用临时切片的数据进行反射，转换为rtParam类型的切片数据
				rvParamTemp := reflect.ValueOf(paramTemp)
				// 不知道为什么? 这里rvParamTemp类型并不是定义的类型，那么我们创建定义的切片类型进行数据转换
				rvParam = reflect.MakeSlice(rtParam, 0, rvParamTemp.Len())
				// 反射方式遍历元素
				for i := 0; i < rvParamTemp.Len(); i++ {
					// 获取下标元素值的 reflect.Value
					tempEle := rvParamTemp.Index(i)
					convertPtr := basicConvert4Interface(rtParam.Elem(), tempEle.Interface())
					// 解析阶段已经限制了切片元素类型不能为指针类型
					rvParam = reflect.Append(rvParam, convertPtr.Elem())
				}
			} else {
				sliceStr := ctx.Query(paramName)
				sliceVal := make([]string, 0)
				err := json.Unmarshal([]byte(sliceStr), &sliceVal)
				if err != nil {
					sliceVal = SpitCommaAndTrim(sliceStr)
				}
				// 根据 rtParam 创建一个切片
				rvParam = reflect.MakeSlice(rtParam, 0, len(sliceVal))
				for _, ele := range sliceVal {
					rvParam = reflect.Append(rvParam, basicConvert(rtParam.Elem(), ele).Elem())
				}
			}
			// 统一转为指针
			rvParamPtr = reflect.New(rtParam)
			rvParamPtr.Elem().Set(rvParam)
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
			reflect.Float32, reflect.Float64, reflect.String, reflect.Bool:
			if strutil.IsBlank(paramName) {
				logger.Error("绑定参数失败：参数名[%s]为空", fun.funName)
				panic(errors.New("绑定参数失败：参数名为空"))
			}
			var val string
			switch {
			case strings.Contains(ctx.FullPath(), strutil.Colon+paramName):
				// 该参数名paramName为路径参数
				val = ctx.Param(paramName)
			case ctx.Request.Method != http.MethodGet:
				// 非get请求，先去表单获取，未获取到再取query
				val = ctx.PostForm(paramName)
				if strutil.IsBlank(val) {
					val = ctx.Query(paramName)
				}
			default:
				// 其他当成query参数取
				val = ctx.Query(paramName)
			}
			// 统一转化为指针
			if val == "" {
				if funParam.definedParamIsPtr {
					rvParamPtr = reflect.Zero(reflect.New(rtParam).Type())
				} else {
					rvParamPtr = reflect.New(rtParam)
					rvParamPtr.Elem().Set(reflect.Zero(rtParam))
				}
			} else {
				rvParamPtr = basicConvert(rtParam, val)
			}
		default:
			msg := fmt.Sprintf("不支持%s类型参数的解析", rtParam.Kind())
			panic(msg)
		}
		// 方法入参填值
		if funParam.definedParamIsPtr {
			rvParams = append(rvParams, rvParamPtr)
		} else {
			rvParams = append(rvParams, rvParamPtr.Elem())
		}
	}
	return rvParams, existCtx
}

func (chh *CommonHttpHandler) copyStructFields(rtStruct reflect.Type, fieldName string, defaultValMap map[string]string) reflect.Type {
	fieldNum := rtStruct.NumField()
	newStructFields := make([]reflect.StructField, 0, fieldNum)
	for i := 0; i < fieldNum; i++ {
		field := rtStruct.Field(i)
		if strutil.IsNotBlank(field.PkgPath) {
			// 字段不可导出
			continue
		}
		var key string
		if strutil.IsNotBlank(fieldName) {
			key = fieldName + strutil.Dot + field.Name
		} else {
			key = field.Name
		}

		rtField := field.Type
		if rtField.Kind() == reflect.Ptr {
			rtField = rtField.Elem()
		}
		if rtField.Kind() == reflect.Struct && field.Anonymous {
			// 内嵌结构体，不加tag
			rtEmbeddedStruct := chh.copyStructFields(rtField, field.Name, defaultValMap)
			field.Type = rtEmbeddedStruct
		} else {
			if rtField.Kind() == reflect.Struct {
				// 非内嵌结构体，加tag，同时也要递归
				if strutil.IsBlank(getDefinedSpecialParamType(getFullPathTypeName(rtField)).String()) {
					// 但注意：特殊结构体（如文件类型的结构体）除外，因为我改变了其结构体，gin为该类型赋值时会报错
					rtNotEmbeddedStruct := chh.copyStructFields(rtField, field.Name, defaultValMap)
					field.Type = rtNotEmbeddedStruct
				}
			}
			tag := field.Tag
			// 如果存在uri(TAG)，就不添加form(TAG)了
			_, existUri := tag.Lookup(ginTagUri)
			if _, ok := tag.Lookup(ginTagForm); !ok && !existUri {
				// `form:"form,default=1"`
				sb := new(strings.Builder)
				sb.WriteString(string(tag))
				fieldNameHump := strutil.FirstLetter2Lower(field.Name)
				if sb.Len() > 0 {
					sb.WriteString(strutil.Space)
				}
				sb.WriteString(ginTagForm)
				sb.WriteString(strutil.Colon)
				sb.WriteString(strutil.Quote)
				sb.WriteString(fieldNameHump)
				if strutil.IsNotBlank(defaultValMap[key]) {
					sb.WriteString(",default=")
					sb.WriteString(defaultValMap[key])
				}
				sb.WriteString(strutil.Quote)
				field.Tag = reflect.StructTag(sb.String())
			}
		}
		newStructFields = append(newStructFields, field)
	}
	return reflect.StructOf(newStructFields)
}

func (chh *CommonHttpHandler) tryToBindUri(ctx *gin.Context, paramPtr any) {
	logger := chh.webContext.logger
	if strings.Contains(ctx.FullPath(), strutil.Colon) {
		// 路径包含冒号，表示路径参数
		rv := reflect.Indirect(reflect.ValueOf(paramPtr))
		rt := rv.Type()
		if rv.Kind() == reflect.Struct && toolkit.NotExistTag(rt, ginTagUri) {
			// 获取所有路径参数名称
			pNames := streams.OfSlice(strings.Split(ctx.FullPath(), strutil.Slash)).
				Filter(func(t string) bool {
					return strings.Contains(t, strutil.Colon)
				}).
				MapIdentity(func(t string) string {
					return strings.ReplaceAll(t, strutil.Colon, strutil.Empty)
				}).ToSlice()
			pMap := make(map[string]string)
			if err := ctx.ShouldBindUri(pMap); err != nil {
				logger.Error("路径参数绑定失败，%v", err)
				panic(errors.New("路径参数绑定失败"))
			}
			for i := 0; i < rt.NumField(); i++ {
				structField := rt.Field(i)
				contains, pName := coll.ContainsIgnoreCaseReturnEle(pNames, structField.Name)
				if contains {
					rvField := rv.Field(i)
					rvField.Set(basicConvert(rvField.Type(), pMap[pName]).Elem())
				}
			}
			return
		}
		if err := ctx.ShouldBindUri(paramPtr); err != nil {
			logger.Error("路径参数绑定失败，%v", err)
			panic(errors.New("路径参数绑定失败"))
		}
	}
}

func (chh *CommonHttpHandler) setDefaultVal(rvParam reflect.Value, fieldName string, defaultValMap map[string]string) {
	rtParam := rvParam.Type()
	for i := 0; i < rvParam.NumField(); i++ {
		structField := rtParam.Field(i)
		if strutil.IsNotBlank(structField.PkgPath) {
			// 字段不可导出
			continue
		}
		var key string
		if strutil.IsNotBlank(fieldName) {
			key = fieldName + strutil.Dot + structField.Name
		} else {
			key = structField.Name
		}

		isPtr := false
		rtField := structField.Type
		if rtField.Kind() == reflect.Ptr {
			rtField = rtField.Elem()
			isPtr = true
		}
		rvField := rvParam.Field(i)
		if rvField.IsZero() {
			if rtField.Kind() == reflect.Struct {
				rvFieldNew := reflect.New(rtField)
				chh.setDefaultVal(rvFieldNew.Elem(), structField.Name, defaultValMap)
				if isPtr {
					rvField.Set(rvFieldNew)
				} else {
					rvField.Set(rvFieldNew.Elem())
				}
			} else {
				// 如果是零值，则赋默认值
				if strutil.IsNotBlank(defaultValMap[key]) {
					structFieldVal := basicConvert(rvField.Type(), defaultValMap[key])
					if isPtr {
						rvField.Set(structFieldVal)
					} else {
						rvField.Set(structFieldVal.Elem())
					}
				}
			}
		}
	}
}

func (chh *CommonHttpHandler) BeforeInvoke(ctx *gin.Context, mapping *HandlerMapping, rvParams []reflect.Value) bool {
	return chh.processor.Before(NewHandlerMappingWrapper(mapping, ctx, rvParams))
}

func (chh *CommonHttpHandler) doInvoke(rvFun reflect.Value, rvParams []reflect.Value) any {
	// 执行方法
	results := rvFun.Call(rvParams)
	if len(results) > 0 {
		// 返回第一个响应的值
		val := results[0]
		if val.IsValid() {
			// 当方法返回值定义为指针类型时，返回结果为nil，此时的nil并非我们理解的nil，用 val.Interface() == nil 为false
			// 这里需要判断下是否为nil，因为后面需要判断nil
			canCallIsNilKinds := []reflect.Kind{reflect.Chan, reflect.Func, reflect.Map,
				reflect.Pointer, reflect.UnsafePointer, reflect.Interface, reflect.Slice}
			if coll.Contains(canCallIsNilKinds, val.Kind()) && val.IsNil() {
				return nil
			}
			// 不为nil，返回真实值
			return val.Interface()
		}
	}
	return nil
}

func (chh *CommonHttpHandler) AfterInvoke(ctx *gin.Context, mapping *HandlerMapping, rvParams []reflect.Value, result any) bool {
	return chh.processor.After(NewHandlerMappingWrapper(mapping, ctx, rvParams), result)
}

func (chh *CommonHttpHandler) responseHtml(data any, existCtx bool, ctx *gin.Context) {
	if existCtx {
		return
	}
	switch modelAndView := data.(type) {
	case string:
		ctx.HTML(http.StatusOK, modelAndView, nil)
	case *string:
		ctx.HTML(http.StatusOK, *modelAndView, nil)
	case ModelAndView:
		ctx.HTML(modelAndView.HttpStatus, modelAndView.View, modelAndView.Model)
	case *ModelAndView:
		ctx.HTML(modelAndView.HttpStatus, modelAndView.View, modelAndView.Model)
	default:
		chh.webContext.logger.Error("无法解析的model and view")
		panic(errors.New("无法解析的model and view"))
	}
}

func (chh *CommonHttpHandler) responseJson(data any, existCtx bool, ctx *gin.Context, fun HandlerMethod) {
	// 如果定义了ctx参数，并且未定义返回值
	// 则框架认为开发者需要自己通过ctx返回数据
	// 框架不做任何返回数据操作
	rtFun := fun.rvFun.Type()
	if rtFun.NumOut() == 0 && existCtx {
		return
	}

	// 如果开发者使用自定义的响应结构体，则框架不做任何默认返回，直接返回响应结果
	if !chh.webContext.useBuiltinRespStruct {
		ctx.JSON(http.StatusOK, data)
		return
	}

	// 响应结果个数为0
	if rtFun.NumOut() == 0 {
		ctx.JSON(http.StatusOK, Ok())
		return
	}
	// 存在响应结果
	if data != nil {
		if strings.HasPrefix(getFullPathTypeName(rtFun.Out(0)),
			builtinResultTypeFullName[:strings.Index(builtinResultTypeFullName, "interface")]) {
			ctx.JSON(http.StatusOK, data)
			return
		}
		ctx.JSON(http.StatusOK, Ok2(data))
	} else {
		ctx.JSON(http.StatusOK, Ok())
	}
}

type ctrlMethodInvokeFilterChain func()

func (my ctrlMethodInvokeFilterChain) DoFilter(_ *HandlerMappingWrapper) {
	my()
}
